#include "session.h"
#include "log.h"
#include <string.h>
#include <malloc.h>

#include "spider.h"

static void _OnSessionCheck(uv_timer_t *handle)
{
    LOG_DEBUG("_OnSessionCheck");
    Session *pSession = (Session *)uv_handle_get_data((uv_handle_t *)handle);
    if (pSession == NULL)
    {
        uv_timer_stop(handle);
        return;
    }

    pSession->OnSessionCheck();
}

static void _OnSessionClose(uv_handle_t *handle)
{
    LOG_DEBUG("_OnSessionClose");
    Session *pSession = (Session *)uv_handle_get_data(handle);
    if (pSession == NULL)
    {
        return;
    }
    if (pSession->m_connectBuf.base)
    {
        LOG_DEBUG("_OnpSessionClose m_connectBuf");
        free(pSession->m_connectBuf.base);
        pSession->m_connectBuf.base = NULL;
    }
    if (pSession->m_targetBuf.base)
    {
        LOG_DEBUG("_OnpSessionClose m_targetBuf");
        free(pSession->m_targetBuf.base);
        LOG_DEBUG("_OnpSessionClose m_targetBuf");
        pSession->m_targetBuf.base = NULL;
    }
    LOG_DEBUG("_OnpSessionClose pSession");
    delete pSession;
}

static void _OnResolvedTarget(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
{
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (status == 0)
    {
        pSession->DoTcpConnectTarget(res->ai_addr);
        uv_freeaddrinfo(res);
    }
    else
    {
        LOG_ERROR("getaddrinfo error: %s", uv_strerror(status));
        pSession->Close();
    }
}

static void _OnUdpResolvedTarget(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
{
    LOG_DEBUG("_OnUdpResolvedTarget");
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (status == 0)
    {
        pSession->DoUdpSendToTarget(res->ai_addr);
        uv_freeaddrinfo(res);
    }
    else
    {
        LOG_ERROR("getaddrinfo error: %s", uv_strerror(status));
        pSession->Close();
    }
}

static void _OnTcpConnectConn(uv_connect_t *req, int status)
{
    LOG_DEBUG("_OnTcpConnectConn");
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (status != 0)
    {
        LOG_ERROR("TcpConnectConn error: %s", uv_strerror(status));
        pSession->Close();
        return;
    }
    pSession->m_status |= SESSION_STATUS_CONN;
    if (pSession->m_status == SESSION_STATUS_RELAY)
    {
        if (pSession->m_model == SESSION_MODEL_TCP)
        {
            pSession->DoTcpConnectedBoth();
        }
        else if (pSession->m_model == SESSION_MODEL_UDP)
        {
            pSession->DoUdpConnectedBoth();
        }
        else
        {
            pSession->Close();
        }
    }
}

static void _OnTcpConnectTarget(uv_connect_t *req, int status)
{
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (status != 0)
    {
        LOG_ERROR("TcpConnectEagle error: %s", uv_strerror(status));
        pSession->Close();
        return;
    }
    pSession->m_status |= SESSION_STATUS_TARGET;
    if (pSession->m_status == SESSION_STATUS_RELAY)
    {
        pSession->DoTcpConnectedBoth();
    }
}

static void _OnTcpAllocBuffConnect(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
    Session *pSession = (Session *)uv_handle_get_data(handle);

    buf->base = pSession->m_connectBuf.base + pSession->m_connectRecvLen;
    buf->len = TCP_BUFF_SIZE - pSession->m_connectRecvLen;
    return;
}

static void _OnTcpAllocBuffTarget(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
    Session *pSession = (Session *)uv_handle_get_data(handle);

    buf->base = pSession->m_targetBuf.base + pSession->m_targetRecvLen;
    buf->len = TCP_BUFF_SIZE - pSession->m_targetRecvLen;
    return;
}

static void _OnTcpReadConnect(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
static void _OnTcpWriteDataTarget(uv_write_t *req, int status);
static void _OnTcpWriteDataConnect(uv_write_t *req, int status);
static void _OnTcpReadTarget(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);

static void _OnTcpWriteDataTarget(uv_write_t *req, int status)
{
    LOG_DEBUG("_OnTcpWriteDataTarget");
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (pSession == NULL)
    {
        free(req);
        return;
    }
    if (status != 0)
    {
        LOG_ERROR("Session: %08x Send Message To Target Failed", pSession->m_sessionId);
        pSession->Close();
    }
    if (pSession->m_connectRecvLen == TCP_BUFF_SIZE)
    {
        uv_read_start((uv_stream_t *)&pSession->m_connectTcp, _OnTcpAllocBuffConnect, _OnTcpReadConnect);
    }
    pSession->m_connectRecvLen = 0;
    free(req);
    return;
}

static void _OnTcpReadConnect(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{
    LOG_DEBUG("_OnTcpReadConnect %d", (int)nread);
    Session *pSession = (Session *)uv_handle_get_data((uv_handle_t *)stream);
    if (nread >= 0 && pSession != NULL)
    {
        pSession->m_lastRecvTick = uv_now(pSession->m_spider->GetLoop());
        uv_write_t *write_req = (uv_write_t *)calloc(1, sizeof(uv_write_t));
        uv_req_set_data((uv_req_t *)write_req, pSession);
        if (write_req != NULL)
        {
            uv_write(write_req, (uv_stream_t *)&pSession->m_targetTcp, &pSession->m_connectBuf, 1, _OnTcpWriteDataTarget);
            return;
        }
        if (pSession->m_connectRecvLen == TCP_BUFF_SIZE)
        {
            uv_read_stop((uv_stream_t *)&pSession->m_connectTcp);
        }
    }
    LOG_DEBUG("_OnTcpReadConnect error:%s", uv_strerror(nread));
    pSession->Close();
    return;
}

static void _OnTcpWriteDataConnect(uv_write_t *req, int status)
{
    LOG_DEBUG("_OnTcpWriteDataConnect");
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (pSession == NULL)
    {
        free(req);
        return;
    }
    if (status != 0)
    {
        LOG_ERROR("Session: %08x Send Message To Conn Failed", pSession->m_sessionId);
        pSession->Close();
    }
    if (pSession->m_targetRecvLen == TCP_BUFF_SIZE)
    {
        uv_read_start((uv_stream_t *)&pSession->m_targetTcp, _OnTcpAllocBuffTarget, _OnTcpReadTarget);
    }
    pSession->m_targetRecvLen = 0;
    free(req);
    return;
}

static void _OnTcpReadTarget(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{
    LOG_DEBUG("_OnTcpReadTarget %d", (int)nread);
    Session *pSession = (Session *)uv_handle_get_data((uv_handle_t *)stream);
    if (nread >= 0 && pSession != NULL)
    {
        pSession->m_lastRecvTick = uv_now(pSession->m_spider->GetLoop());
        uv_write_t *write_req = (uv_write_t *)calloc(1, sizeof(uv_write_t));
        uv_req_set_data((uv_req_t *)write_req, pSession);
        if (write_req != NULL)
        {
            uv_write(write_req, (uv_stream_t *)&pSession->m_connectTcp, &pSession->m_targetBuf, 1, _OnTcpWriteDataConnect);
            return;
        }
        if (pSession->m_targetRecvLen == TCP_BUFF_SIZE)
        {
            uv_read_stop((uv_stream_t *)&pSession->m_targetTcp);
        }
    }
    LOG_DEBUG("_OnTcpReadTarget error:%s", uv_strerror(nread));
    pSession->Close();
    return;
}

static void _OnUdpAllocBuffConnect(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
    Session *pSession = (Session *)uv_handle_get_data(handle);
    LOG_DEBUG("_OnUdpAllocBuffConnect suggested_size %ld m_udpHeaderLen %u", suggested_size, pSession->m_udpHeaderLen);
    buf->base = pSession->m_connectBuf.base + pSession->m_connectRecvLen;
    buf->len = UDP_BUFF_SIZE - pSession->m_connectRecvLen;
    return;
}

static void _OnUdpAllocBuffTarget(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
    Session *pSession = (Session *)uv_handle_get_data(handle);
    LOG_DEBUG("_OnUdpAllocBuffTarget suggested_size %ld m_udpHeaderLen %u", suggested_size, pSession->m_udpHeaderLen);
    buf->base = pSession->m_targetBuf.base + pSession->m_udpHeaderLen - pSession->m_targetRecvLen;
    buf->len = UDP_BUFF_SIZE - pSession->m_udpHeaderLen - pSession->m_targetRecvLen;
    return;
}

static void _OnUdpWriteDataTarget(uv_udp_send_t *req, int status)
{
    LOG_DEBUG("_OnUdpWriteDataTarget");
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (pSession == NULL || req == NULL)
    {
        free(req);
        return;
    }
    if (status != 0)
    {
        LOG_ERROR("Session: %08x Send Message Failed", pSession->m_sessionId);
        pSession->Close();
        free(req);
        return;
    }
    pSession->m_connectRecvLen = 0;
    free(req);
    return;
}

static void _OnUdpWriteDataConnect(uv_write_t *req, int status)
{
    LOG_DEBUG("_OnUdpWriteDataConnect");
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (pSession == NULL || req == NULL)
    {
        free(req);
        return;
    }
    if (status != 0)
    {
        LOG_ERROR("Session: %08x Send Message To Conn Failed", pSession->m_sessionId);
        pSession->Close();
    }
    pSession->m_targetRecvLen = 0;
    free(req);
    return;
}

static void _OnUdpReadConnect(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
{
    LOG_DEBUG("_OnUdpReadConnect %d", (int)nread);
    Session *pSession = (Session *)uv_req_get_data((uv_req_t *)stream);
    if (nread < 0)
    {
        LOG_DEBUG("_OnUdpReadConnect error:%s", uv_strerror(nread));
        pSession->Close();
        return;
    }
    else if (nread == 0)
    {
        return;
    }
    pSession->m_lastRecvTick = uv_now(pSession->m_spider->GetLoop());
    pSession->m_connectRecvLen += nread;
    if (nread < 4)
    {
        LOG_DEBUG("package too short");
        return;
    }
    uint16_t data_len = *(uint16_t *)(buf->base);
    if (!pSession->m_hastarget)
    {
        uint8_t atype = buf->base[3];
        char *cmdPos = buf->base;
        if (atype == SOCKS5_ATYP_IPV4)
        {
            if (nread < 10)
            {
                return;
            }
            pSession->m_udpHeaderLen = 10;
            snprintf(pSession->m_targetInfo, TARGET_INFO_SIZE, "%u.%u.%u.%u", (uint8_t)cmdPos[4], (uint8_t)cmdPos[5],
                     (uint8_t)cmdPos[6], (uint8_t)cmdPos[7]);
            pSession->m_targetPort = *(uint16_t *)(cmdPos + 8);
        }
        else if (atype == SOCKS5_ATYP_DOMAINNAME)
        {
            if (nread < 5)
            {
                return;
            }
            uint8_t domainLen = cmdPos[4];
            if (nread < 7 + domainLen)
            {
                return;
            }
            memcpy(pSession->m_targetInfo, cmdPos + 5, domainLen);
            pSession->m_targetPort = *(uint16_t *)(cmdPos + 5 + domainLen);
            pSession->m_udpHeaderLen = 5 + domainLen + 2;
        }
        else
        {
            LOG_DEBUG("atype Not Supported");
            return;
        }
        LOG_INFO("Udp Proxy targetInfo [%s:%u]", pSession->m_targetInfo, htons( pSession->m_targetPort));
        memcpy(pSession->m_targetBuf.base, pSession->m_connectBuf.base, pSession->m_udpHeaderLen);
        struct addrinfo hints;
        hints.ai_family = PF_INET;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
        hints.ai_flags = 0;
        uv_req_set_data((uv_req_t *)&pSession->m_resolver, pSession);
        int r = uv_getaddrinfo(pSession->m_spider->GetLoop(), &pSession->m_resolver, _OnUdpResolvedTarget, pSession->m_targetInfo,
                               std::to_string(htons(pSession->m_targetPort)).c_str(), &hints);
        if (r)
        {
            LOG_ERROR("getaddrinfo [%s] call error %s", pSession->m_targetInfo, uv_err_name(r));
            return;
        }
    }
    else
    {
        LOG_DEBUG("send_buf targetUdp  %d", (int)pSession->m_connectRecvLen - pSession->m_udpHeaderLen);
        uv_buf_t send_buf = {pSession->m_connectBuf.base + pSession->m_udpHeaderLen, (size_t)(data_len - pSession->m_udpHeaderLen)};
        uv_udp_send_t *send_req = (uv_udp_send_t *)calloc(1, sizeof(uv_udp_send_t));
        uv_req_set_data((uv_req_t *)send_req, pSession);
        if (send_req != NULL)
        {
            LOG_DEBUG("DoUdpSendToTarget len %ld", send_buf.len);
            uv_udp_send(send_req, &pSession->m_targetUdp, &send_buf, 1, (const sockaddr *)&pSession->m_targetAddr, _OnUdpWriteDataTarget);
            return;
        }
    }
}

static void _OnUdpReadTarget(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const sockaddr *addr, unsigned flags)
{
    LOG_DEBUG("_OnUdpReadTarget %d", (int)nread);
    Session *pSession = (Session *)uv_handle_get_data((uv_handle_t *)handle);

    if (nread > 0)
    {
        pSession->m_lastRecvTick = uv_now(pSession->m_spider->GetLoop());
        if (!pSession->m_hastarget)
        {
            LOG_DEBUG("udp drop packet");
            return;
        }
        pSession->m_targetRecvLen += nread;        
        uv_buf_t send_buf = {pSession->m_targetBuf.base, pSession->m_targetRecvLen + pSession->m_udpHeaderLen};
        uint16_t *data_len = (uint16_t *)pSession->m_targetBuf.base;
        *data_len = pSession->m_targetRecvLen + pSession->m_udpHeaderLen;
        uv_write_t *write_req = (uv_write_t *)calloc(1, sizeof(uv_write_t));
        uv_req_set_data((uv_req_t *)write_req, pSession);
        if (write_req != NULL)
        {
            LOG_DEBUG("DoUdpSendToConnect len %ld", send_buf.len);
            uv_write(write_req, (uv_stream_t *)&pSession->m_connectTcp, &send_buf, 1, _OnUdpWriteDataConnect);
            return;
        }
    }
    else if (nread == 0)
    {
        return;
    }
    LOG_DEBUG("_OnUdpReadTarget error:%s", uv_strerror(nread));
    pSession->Close();
    return;
}

static void _OnSendSignalToDataConn(uv_write_t *req, int status)
{
    LOG_DEBUG("_OnSendSignalToDataConn");
    auto pSession = (Session *)uv_req_get_data((uv_req_t *)req);
    if (pSession == nullptr)
    {
        free(req);
        return;
    }
    if (status != 0)
    {
        LOG_ERROR("Session [%x] Send Signal To DataConn Failed", pSession->m_sessionId);
        pSession->Close();
    }
    free(req);
    return;
}

bool Session::Init(Spider *spider, uint8_t model, uint8_t *data)
{
    MessageRelay *msg = (MessageRelay *)data;
    m_sessionId = msg->sessionId;
    m_spider = spider;
    m_model = model;
    m_commandTimeout = spider->m_commandTimeout;
    m_idleTimeout = spider->m_idleTimeout;
    uv_tcp_init(m_spider->GetLoop(), &m_connectTcp);    
    if (g_BindAddr.size() > 0) {
        // 设置本地地址绑定
        struct sockaddr_in bind_addr;
        uv_ip4_addr(g_BindAddr.c_str(), 0, &bind_addr); // 使用你想要绑定的本地IP地址，端口号设为0以让系统自动分配
        uv_tcp_bind(&m_connectTcp, (const struct sockaddr*) &bind_addr, 0);
    }
    uv_tcp_init(m_spider->GetLoop(), &m_targetTcp);
    if (g_BindAddr.size() > 0) {
        // 设置本地地址绑定
        struct sockaddr_in bind_addr;
        uv_ip4_addr(g_BindAddr.c_str(), 0, &bind_addr); // 使用你想要绑定的本地IP地址，端口号设为0以让系统自动分配
        uv_tcp_bind(&m_targetTcp, (const struct sockaddr*) &bind_addr, 0);
    }
    uv_udp_init(m_spider->GetLoop(), &m_targetUdp);
    if (g_BindAddr.size() > 0) {
        // 设置本地地址绑定
        struct sockaddr_in bind_addr;
        uv_ip4_addr(g_BindAddr.c_str(), 0, &bind_addr); // 使用你想要绑定的本地IP地址，端口号设为0以让系统自动分配
        uv_udp_bind(&m_targetUdp, (const struct sockaddr*) &bind_addr, 0);
    }
    
    uv_timer_init(m_spider->GetLoop(), &m_sessionTimer);
    uv_handle_set_data((uv_handle_t *)&m_sessionTimer, this);
    uv_handle_set_data((uv_handle_t *)&m_connectTcp, this);
    uv_handle_set_data((uv_handle_t *)&m_targetTcp, this);
    m_lastRecvTick = uv_now(m_spider->GetLoop());
    uv_timer_start(&m_sessionTimer, _OnSessionCheck, 0, g_timerRepeat);

    if (m_model == SESSION_MODEL_TCP)
    {
        DoMessageTcp((MessageTcp *)data);
    }
    else if (m_model == SESSION_MODEL_UDP)
    {
        DoMessageUdp((MessageUdp *)data);
    } else {
        Close();
        return false;
    }
    return true;
}

void Session::OnSessionCheck()
{
    if (m_status != SESSION_STATUS_RELAY)
    {
        if (m_lastRecvTick + m_commandTimeout < uv_now(m_spider->GetLoop()))
        {
            LOG_ERROR("Session: %08x command Timeout", m_sessionId);
            Close();
            return;
        }
    }
    else
    {
        if (m_lastRecvTick + m_idleTimeout < uv_now(m_spider->GetLoop()))
        {
            LOG_DEBUG("Session: %08x Idle Timeout", m_sessionId);
            Close();
            return;
        }
    }
}

void Session::Close()
{
    LOG_DEBUG("Session: %08x Close", m_sessionId);
    if (uv_is_active((uv_handle_t *)&m_sessionTimer))
    {
        LOG_DEBUG("Session Close uv_timer_stop");
        uv_timer_stop(&m_sessionTimer);
        
    }
    if (!uv_is_closing((uv_handle_t *)&m_targetUdp))
    {
        LOG_DEBUG("Session Close m_targetUdp");
        uv_close((uv_handle_t *)&m_targetUdp, NULL);
    }
    if (!uv_is_closing((uv_handle_t *)&m_targetTcp))
    {
        LOG_DEBUG("Session Close m_targetTcp");
        uv_close((uv_handle_t *)&m_targetTcp, NULL);
    }
    if (!uv_is_closing((uv_handle_t *)&m_connectTcp))
    {
        LOG_DEBUG("Session Close m_connectTcp");
        uv_close((uv_handle_t *)&m_connectTcp, _OnSessionClose);
    }
}

void Session::DoMessageTcp(MessageTcp *msg)
{
    LOG_DEBUG("DoMessageTcp");
    m_hastarget = true;
    memcpy(m_targetInfo, msg->target, msg->targetLen);
    m_targetPort = msg->targetPort;
    struct sockaddr_in connAddr;
    connAddr.sin_family = AF_INET;
    connAddr.sin_addr.s_addr = msg->eagleAddr;
    connAddr.sin_port = htons(msg->eaglePort);
    LOG_DEBUG("connect conn tcp:%x:%u", msg->eagleAddr, msg->eaglePort);
    LOG_INFO("Tcp Proxy targetInfo [%s:%u]", m_targetInfo, htons(m_targetPort));

    uv_req_set_data((uv_req_t *)&m_connectTcpReq, this);
    uv_tcp_connect(&m_connectTcpReq, &m_connectTcp, (const struct sockaddr *)&connAddr, _OnTcpConnectConn);

    struct addrinfo hints;
    hints.ai_family = PF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = 0;
    uv_req_set_data((uv_req_t *)&m_resolver, this);
    int r = uv_getaddrinfo(m_spider->GetLoop(), &m_resolver, _OnResolvedTarget, m_targetInfo,
                           std::to_string(htons(m_targetPort)).c_str(), &hints);
    if (r)
    {
        LOG_ERROR("getaddrinfo [%s] call error %s", m_targetInfo, uv_err_name(r));
        return;
    }
}

void Session::DoTcpConnectTarget(struct sockaddr *target)
{
    uv_req_set_data((uv_req_t *)&m_targetTcpReq, this);
    uv_tcp_connect(&m_targetTcpReq, &m_targetTcp, target, _OnTcpConnectTarget);
}

void Session::DoTcpConnectedBoth()
{
    LOG_DEBUG("DoTcpConnectedBoth");
    m_connectBuf.base = (char *)calloc(TCP_BUFF_SIZE, sizeof(char));
    if (!m_connectBuf.base)
    {
        Close();
    }
    m_connectBuf.len = TCP_BUFF_SIZE;
    m_targetBuf.base = (char *)calloc(TCP_BUFF_SIZE, sizeof(char));
    if (!m_targetBuf.base)
    {
        Close();
    }
    m_targetBuf.len = TCP_BUFF_SIZE;
    
    uv_handle_set_data((uv_handle_t *)&m_connectTcp, this);
    uv_handle_set_data((uv_handle_t *)&m_targetTcp, this);
    SendSignalToDataConn();
    uv_read_start((uv_stream_t *)&m_connectTcp, _OnTcpAllocBuffConnect, _OnTcpReadConnect);
    uv_read_start((uv_stream_t *)&m_targetTcp, _OnTcpAllocBuffTarget, _OnTcpReadTarget);
    m_status = SESSION_STATUS_RELAY;
}

void Session::DoMessageUdp(MessageUdp *msg)
{
    struct sockaddr_in connAddr;
    connAddr.sin_family = AF_INET;
    connAddr.sin_addr.s_addr = msg->eagleAddr;
    connAddr.sin_port = htons(msg->eaglePort);
    LOG_DEBUG("connect conn tcp:%x:%u", msg->eagleAddr, msg->eaglePort);

    m_status |= SESSION_STATUS_TARGET;
    uv_req_set_data((uv_req_t *)&m_connectTcpReq, this);    
    uv_tcp_connect(&m_connectTcpReq, &m_connectTcp, (const struct sockaddr *)&connAddr, _OnTcpConnectConn);
}

void Session::DoUdpConnectedBoth()
{
    m_connectBuf.base = (char *)calloc(UDP_BUFF_SIZE, sizeof(char));
    if (!m_connectBuf.base)
    {
        Close();
    }
    m_connectBuf.len = UDP_BUFF_SIZE;
    m_targetBuf.base = (char *)calloc(UDP_BUFF_SIZE, sizeof(char));
    if (!m_targetBuf.base)
    {
        Close();
    }
    m_targetBuf.len = UDP_BUFF_SIZE;

    uv_handle_set_data((uv_handle_t *)&m_connectTcp, this);
    uv_handle_set_data((uv_handle_t *)&m_targetUdp, this);
    SendSignalToDataConn();
    uv_read_start((uv_stream_t *)&m_connectTcp, _OnUdpAllocBuffConnect, _OnUdpReadConnect);
    uv_udp_recv_start(&m_targetUdp, _OnUdpAllocBuffTarget, _OnUdpReadTarget);
    m_status = SESSION_STATUS_RELAY;
}

void Session::DoUdpSendToTarget(struct sockaddr *target)
{
    LOG_DEBUG("DoUdpSendToTarget");
    m_hastarget = true;
    char ip[INET6_ADDRSTRLEN];
    uv_ip4_name((struct sockaddr_in *)target, ip, sizeof(ip));
    LOG_DEBUG("_OnUdpResolvedTarget Resolved: %s %u", ip, ntohs(((struct sockaddr_in *)target)->sin_port));
    memcpy(&m_targetAddr, target, sizeof(struct sockaddr));
    uint16_t data_len = *(uint16_t *)(m_connectBuf.base);
    if (data_len > m_connectRecvLen) {
        return;
    }
    uv_buf_t send_buf = {m_connectBuf.base + m_udpHeaderLen, (size_t)(data_len - m_udpHeaderLen)};
    uv_udp_send_t *send_req = (uv_udp_send_t *)calloc(1, sizeof(uv_udp_send_t));
    uv_req_set_data((uv_req_t *)send_req, this);
    if (send_req != NULL)
    {
        LOG_DEBUG("DoUdpSendToTarget len %ld", send_buf.len);
        uv_udp_send(send_req, &m_targetUdp, &send_buf, 1, &m_targetAddr, _OnUdpWriteDataTarget);
        return;
    }
    Close();
}

void Session::SendSignalToDataConn()
{
    uv_write_t *writeReq = (uv_write_t *)calloc(1, sizeof(uv_write_t));
    if (!writeReq)
    {
        LOG_ERROR("Session: %08x calloc write Req Failed", m_sessionId);
        Close();
        return;
    }
    uv_handle_set_data((uv_handle_t *)writeReq, (void *)this);
    uv_buf_t buf = uv_buf_init((char *)&m_sessionId, sizeof(uint32_t));
    if (uv_write(writeReq, (uv_stream_t *)&m_connectTcp, &buf, 1, _OnSendSignalToDataConn) < 0)
    {
        LOG_ERROR("Session: %08x write Req Failed", m_sessionId);
        free(writeReq);
        Close();
    }
}
